﻿using System;
using System.Linq;

namespace Borg.Framework
{
    public class SlotComboBox : ComboBox, IAttachable
    {
        public SlotComboBox()
        {
            Enabled = false;
        }

        public void Attach(SlotInfo slot)
        {
            Slot = slot;
            
            Slot.Registered += Registered;
            Slot.Deregistered += Deregistered;
            
            Runtime.Repository.PluginAdded += PluginAdded;
            Runtime.Repository.PluginRemoved += PluginRemoved;
            
            Items.Clear();

            foreach (var pti in Runtime.Repository.PlugTypeInfos.
                Where(pti => pti.Name.Equals(Slot.Name)))
                Items.Add(pti, pti);

            Enabled = true;
        }

        private void Deregistered(object sender, RegisterEventArgs args)
        {
            if (SelectedItem.Key == args.PlugTypeInfo)
                SelectedIndex = -1;
        }

        public void Detach()
        {
            Enabled = false;
            Items.Clear();
            
            Slot.Registered -= Registered;
            Slot.Deregistered -= Deregistered;
            
            Runtime.Repository.PluginAdded -= PluginAdded;
            Runtime.Repository.PluginRemoved -= PluginRemoved;
            
            Slot = null;
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            if (Slot != null)
                Detach();
        }

        protected override void OnSelectedIndexChanged(EventArgs e)
        {
            base.OnSelectedIndexChanged(e);

            if (noUpdate || (SelectedIndex < 0))
                return;

            if (Slot.RegisteredPlugTypeInfos.Any(pti => pti == SelectedItem.Key))
                return;

            Slot.Register((PlugTypeInfo)SelectedItem.Key);
        }

        private void PluginAdded(object sender, PluginEventArgs args)
        {
            foreach (var pti in
                from eti in args.ExtensionTypeInfos
                from pti in eti.PlugTypeInfos
                where pti.Name.Equals(Slot.Name)
                select pti)
                Items.Add(pti, pti);
        }

        private void PluginRemoved(object sender, PluginEventArgs args)
        {
            foreach (var pti in
                from eti in args.ExtensionTypeInfos
                from pti in eti.PlugTypeInfos
                where pti.Name.Equals(Slot.Name)
                select pti)
                Items.Remove(pti);
        }

        private void Registered(object sender, RegisterEventArgs args)
        {
            noUpdate = true;
            SelectedIndex = Items.IndexOf(args.PlugTypeInfo);
            noUpdate = false;
        }

        public SlotInfo Slot { get; private set; }
    }
}

